﻿#include <iostream>
#include <stdlib.h>
#include <string>
#include <Windows.h>
#include <fstream>
#include <regex>
#include <sstream>
#include <iomanip>
#include "Interpreter.h"
#include "UserCommand.h"
#include "CatalogManager.h"
#include "SysException.h"
#include "api.h"
#include "RecordManager.h"
using namespace std;

CInterpreter::CInterpreter(shared_ptr<API> m_api, shared_ptr<CCatalog> m_catalog)
{
	this->m_api = m_api;
	this->m_catalog = m_catalog;
	m_result = "";

	cout << endl
		<< "         _       __  ______  __     ______  ____    __  ___  ______   " << endl
		<< "        | |     / / / ____/ / /    / ____/ / __ \\  /  |/  / / ____/  " << endl
		<< "        | | /| / / / __/   / /    / /     / / / / / /|_/ / / __/      " << endl
		<< "        | |/ |/ / / /___  / /___ / /___  / /_/ / / /  / / / /___      " << endl
		<< "        |__/|__/ /_____/ /_____/ \\____/  \\____/ /_/  /_/ /_____/    " << endl << endl;

	cout << "  *************************************************************************" << endl
		<< "  **                         Welcom to MiniSQL!                          **" << endl
		<< "  **            Copyright by Tang Xisong, Li Ming, Xu Chaoying           **" << endl
		<< "  **           College of Computer Science, Zhejiang University          **" << endl
		<< "  **                             2014.11                                 **" << endl
		<< "  *************************************************************************" << endl << endl;
}


CInterpreter::~CInterpreter()
{
}

void CInterpreter::StartMiniSQL() // 开始程序
{
	string userInput, result;
	CUserCommand newCommand;

	while (1)
	{
		userInput = ReadUserInput(); // 读取用户的输入
		try {
			newCommand = ParseCommand(userInput); // 语法检查，并将用户输入解析成内部命令
			Execute(newCommand); // 执行该条命令
		}
		catch (CSysException e){
			if (e.getError() != "quit")
				e.print();
			else
				break;
		}
	}
}

string CInterpreter::ReadUserInput() // 读取用户输入
{
	string strLine; // 一行的输入
	string str = "";
	bool IsComEnd(string);

	cout << "MiniSql >> ";
	while (1)
	{
		getline(cin, strLine); // 读取一行字符串
		str = str + strLine; // 将新一行的字符串连接
		if (IsComEnd(strLine)) // 单行或多行命令输入结束
		{
			return str;
		}
		else
		{
			str = str + " ";
			cout << "        >> ";
		}
	}
}

int GetValueType(string str)
{
	if ((str[0] == '\'' && str[str.length() - 1] == '\'') || (str[0] == '\"' && str[str.length() - 1] == '\"')) // char类型
	{
		str = regex_replace(str, (regex)"\\s*\'\\s*", ""); // 去掉str两边的" ' "
		str = regex_replace(str, (regex)"\\s*\"\\s*", ""); // 去掉str两边的" ' "
		return str.length(); // 返回char的长度
	}
	else if (regex_match(str, (regex)"\\d+\\.\\d+")) // 有小数点
	{
		return 0; // 返回float
	}
	else if (regex_match(str, (regex)"\\d+"))
	{
		return -1;

	}
	return -2; // 不正常数值处理
}

vector<Condition> ConditionSeparator(string cons) throw(CSysException) // 将字符串con解析成select或delete要用的条件vector
{
	vector<Condition> vNewCon;
	cons = regex_replace(cons, (regex)" and ", " , "); // 把and连接词替换成‘，’方便处理
	const regex separateCon("[^,]+"); //根据，把每个条件分开
	const sregex_token_iterator consIterator;
	vector<Condition> newCondition;

	for (sregex_token_iterator i(cons.begin(), cons.end(), separateCon); i != consIterator; ++i)
	{
		Condition newCon;
		string con = (string)*i;
		con = regex_replace(con, (regex)"\\s?<>\\s?", " - "); // 确保操作符和前后字符串之间有空格隔开
		con = regex_replace(con, (regex)"\\s?<=\\s?", " ! ");
		con = regex_replace(con, (regex)"\\s?>=\\s?", " : ");
		con = regex_replace(con, (regex)"\\s?=\\s?", " = ");
		con = regex_replace(con, (regex)"\\s?<\\s?", " < ");
		con = regex_replace(con, (regex)"\\s?>\\s?", " > ");

		const regex separateCon("\\S+"); // 把列属性里的单个元素（列名、类型等）分开
		const sregex_token_iterator conIterator;
		int count = 0;
		string strWord;
		for (sregex_token_iterator j(con.begin(), con.end(), separateCon); j != conIterator; ++j)
		{
			count++;
			strWord = (string)*j;
			switch (count)
			{
			case 1: 
			{
				newCon.conCol = strWord;                  
				break;
			}
			case 2:
			{
				if (strWord == "=")
					newCon.conOperator = COMP_EQUAL;
				else if (strWord == "-")
					newCon.conOperator = COMP_NOT_EQUAL;
				else if (strWord == "<")
					newCon.conOperator = COMP_LESS;
				else if (strWord == ">")
					newCon.conOperator = COMP_LARGE;
				else if (strWord == "!")
					newCon.conOperator = COMP_LESS_EQUAL;
				else if (strWord == ":")
					newCon.conOperator = COMP_LARGE_EQUAL;
				else
				{
					CSysException e("Illegal oprator");
					throw e;
				}

				break;
			}
			case 3:
			{
				newCon.conValueType = GetValueType(strWord); // 获取该字符串的类型
				if (newCon.conValueType == -2)
				{
					CSysException e("Wrong value type to compare");
					throw e;
				}
				newCon.conValue = strWord;      
				break;
			}
			default:
			{
				CSysException e("Wrong condition description");
				throw e;
			}
			}
		}
		if (newCon.conValue == "")
		{
			CSysException e("No value to compare");
			throw e;
		}
		vNewCon.push_back(newCon);  
	} // end of for(i)
	return vNewCon;
}

CUserCommand CInterpreter::ParseCommand(string str) throw(CSysException) // 解析用户输入
{
	CUserCommand newCommand;
	string tableAttr;

	str = regex_replace(str, (regex)"(,|\\(|\\)|;)", " $1 "); // 给 ,;()四个符号前后加上空格
	str = regex_replace(str, (regex)"\\s+", " "); // 去掉多余的空格

	/*--------------------判断是否是create table--------------------*/
	const regex patCreateT("\\s?create table (\\w+) \\( (.+) \\) ; ");
	match_results<string::const_iterator> resCreateT;
	bool bCreateT = regex_match(str, resCreateT, patCreateT);
	if (bCreateT) // 是create table命令
	{
		newCommand.SetOperate(OP_CREATE); // 设置操作为create table
		newCommand.SetTableName(resCreateT[1]); // 设置表的名字

		//////////////////////////表的列属性解析//////////////////////////
		tableAttr = resCreateT[2]; // 创建表语句括号里包含表属性信息的字符串
		const regex separateCol("[^,]+"); //根据，把每个表的列属性分开
		const sregex_token_iterator colsIterator;
		vector<Attribute> newTableAttr;

		for (sregex_token_iterator i(tableAttr.begin(), tableAttr.end(), separateCol); i != colsIterator; ++i)
		{
			
			Attribute newAttribute; // 新建一个列属性

			string col = (string)*i;
			const regex separateAttr("[\^ ()]+"); // 把列属性里的单个元素（列名、类型等）分开
			const sregex_token_iterator attrIterator;
			int count = 0; 
			bool bPK = false;
			for (sregex_token_iterator j(col.begin(), col.end(), separateAttr); j != attrIterator; ++j)
			{
				count++;
				string attr = (string)*j;

				switch (count)
				{
				case 1:
				{
					if (attr != "primary")
						newAttribute.attrName = attr;
					else
						bPK = true;
					break;
				}
				case 2:
				{
					if (attr == "int")
						newAttribute.attrType = -1;
					if (attr == "float")
						newAttribute.attrType = 0;
					if (attr == "char")
						newAttribute.attrType = 1;
					break;
				}
				case 3:
				{
					if (attr == "unique")
						newAttribute.attrIsUnique = true;
					if (attr >= "1" || attr <= "255")
					{
						stringstream ss(attr);
						ss >> newAttribute.attrType;
					}
					break;
				}
				case 4:
				{
					if (attr == "unique")
						newAttribute.attrIsUnique = true;
					break;
				}
				default:
				{
					// 未通过语法检查的语句
					CSysException e("You have an error in your SQL syntax");
					throw e;
				}
				} // end of switch(count)
			} // end of for(j)
			if (!bPK)
				newTableAttr.push_back(newAttribute);
		}// end of for(i)
		newCommand.SetTableAttr(newTableAttr);
		///////////////////////////////////////////////////////
		
		///////////////////解析primary key/////////////////////
		const regex patKey(".*primary key \\( (\\w+) \\).*");
		match_results<string::const_iterator> reKey;
		bool bKey = regex_match(tableAttr, reKey, patKey);
		if (bKey)
			newCommand.SetPrimaryKey(reKey[1]);
		else
		{
		    // 未通过语法检查的语句，没有key
			CSysException e("Primary key not found");
			throw e;
		}
		//////////////////////////////////////////////////////

		return newCommand;
	} // end of if(bCreateT) 
	
	/*--------------------判断是否是drop table--------------------*/
	const regex patDropT("\\s?drop table (\\w+) ; ");
	match_results<string::const_iterator> resDropT;
	bool bDropT = regex_match(str, resDropT, patDropT);
	if (bDropT) // 是drop table命令
	{
		newCommand.SetOperate(OP_DROP); // 设置操作为drop table
		newCommand.SetTableName(resDropT[1]); // 设置表的名字
		return newCommand;
	}

	/*--------------------判断是否是create index--------------------*/
	const regex patCreateI("\\s?create index (\\w+) on (\\w+) \\( (\\w+) \\) ; ");
	match_results<string::const_iterator> resCreateI;
	bool bCreateI = regex_match(str, resCreateI, patCreateI);
	if (bCreateI) // 是create index命令
	{
		newCommand.SetOperate(OP_CREATE_INDEX); // 设置操作为create index
		newCommand.SetIndexName(resCreateI[1]); // 设置index的名字
		newCommand.SetTableName(resCreateI[2]); // 设置表的名字
		newCommand.SetIndexAttr(resCreateI[3]); // 设置建立索引的列名
		return newCommand;
	}

	/*--------------------判断是否是drop index--------------------*/
	const regex patDropI("\\s?drop index (\\w+) ; ");
	match_results<string::const_iterator> resDropI;
	bool bDropI = regex_match(str, resDropI, patDropI);
	if (bDropI) // 是drop index命令
	{
		newCommand.SetOperate(OP_DROP_INDEX); // 设置操作为drop index
		newCommand.SetIndexName(resDropI[1]); // 设置index的名字
		return newCommand;
	}

	/*--------------------判断是否是select--------------------*/
	//const regex patSelect("\\s?select (.+) from (\\w+)( where (.+))? ; "); //不能判断重复输入语句
	const regex patSelect("\\s?select ([\^from]+) from (\\w+)( where (.+))? ; "); 
	match_results<string::const_iterator> resSelect;
	bool bSelect = regex_match(str, resSelect, patSelect);  
	cout << "==" << resSelect[0] << "==" << resSelect[1] << "==" << resSelect[2] << "==" << resSelect[3] << "==" << endl;
	if (bSelect) // 是Select命令
	{
		newCommand.SetOperate(OP_SELECT); // 设置操作为select
		newCommand.SetTableName(resSelect[2]); // 设置表的名字
		/////////////////////////所选择的列的处理///////////////////////  
		vector<string> newSelectedCols;
		
		string selectedCols = resSelect[1];
		if (selectedCols[selectedCols.size() - 1] == ',')
		{
			CSysException e("Unnecessary ',' in the selected cols");
			throw e;
		}
		const regex separateSC("[\^ ,]+"); // 把列属性里的单个元素（列名、类型等）分开
		const sregex_token_iterator SCIterator;
		int count = 0;
		string strCol;
		for (sregex_token_iterator i(selectedCols.begin(), selectedCols.end(), separateSC); i != SCIterator; ++i)
		{
			strCol = (string)*i;
			newSelectedCols.push_back(strCol);                
		}
		newCommand.SetSelectCol(newSelectedCols);

		/////////////////////////选择的条件处理/////////////////////////
		string con = resSelect[4]; 
		if (con != "") // 如果resSelect[4]不为空说明有where条件
		{
			newCommand.SetWhereCondition(true); 
			try{
				newCommand.SetCondition(ConditionSeparator(con)); // 解析出的条件存入newCommand
			}
			catch (string err){
				cout << "Error: " << err << "!" << endl;
				StartMiniSQL();
			}
		}
		else // 没有where条件限制
		{
			newCommand.SetWhereCondition(false);
		}
		return newCommand;
	}

	/*--------------------判断是否是insert--------------------*/
	const regex patInsert("\\s?insert into (\\w+) values \\( (.+) \\) ; ");
	match_results<string::const_iterator> resInsert;
	bool bInsert = regex_match(str, resInsert, patInsert);
	if (bInsert) // 是Insert命令
	{
		newCommand.SetOperate(OP_INSERT); // 设置操作为insert
		newCommand.SetTableName(resInsert[1]); // 设置表的名字
		/////////////////////////插入信息的处理/////////////////////////
		vector<string> newValues;

		string strInserts = resInsert[2];
		const regex separateInserts("[\^ ,]+"); // 把列属性里的单个元素（列名、类型等）分开
		const sregex_token_iterator SIIterator;
		int count = 0;
		string strVal;
		for (sregex_token_iterator i(strInserts.begin(), strInserts.end(), separateInserts); i != SIIterator; ++i)
		{
			strVal = (string)*i;
			newValues.push_back(strVal);   
		}
		newCommand.SetInsertValue(newValues);
		return newCommand;
	}

	/*--------------------判断是否是delete--------------------*/
	const regex patDel("\\s?delete from (\\w+)( where (.+))? ; ");
	match_results<string::const_iterator> resDel;
	bool bDel = regex_match(str, resDel, patDel);
	if (bDel) // 是delete命令
	{
		newCommand.SetOperate(OP_DELETE); // 设置操作为delete
		newCommand.SetTableName(resDel[1]); // 设置表的名字
		/////////////////////////删除条件的处理///////////////////////// 
		string con = resDel[3];
		if (con != "") // 如果resDel[3]不为空说明有where条件
		{
			newCommand.SetWhereCondition(true);
			try{
				newCommand.SetCondition(ConditionSeparator(con)); // 解析出的条件存入newCommand
			}
			catch (string err){
				cout << "Error: " << err << "!" << endl;
				StartMiniSQL();
			}	
		}
		else // 没有where条件限制
		{
			newCommand.SetWhereCondition(false);
		}
		return newCommand;
	}

	/*--------------------判断是否是quit--------------------*/
	const regex patQuit("\\s?quit ; ");
	match_results<string::const_iterator> resQuit;
	bool bQuit = regex_match(str, resQuit, patQuit);
	if (bQuit) // 是Quit命令
	{
		newCommand.SetOperate(OP_QUIT); // 设置操作为Quit
		return newCommand;
	}

	/*--------------------判断是否是execute file--------------------*/
	const regex patExeFile("\\s?execfile (\\S+) ; ");
	match_results<string::const_iterator> resExeFile;
	bool bExeFile = regex_match(str, resExeFile, patExeFile);
	if (bExeFile) // 是执行脚本文件命令
	{
		newCommand.SetOperate(OP_EXEFILE); // 设置操作为EXE FILE
		newCommand.SetFileName(resExeFile[1]);
		return newCommand;
	}
	CSysException e("You have an error in your SQL syntax");
	throw(e);
	
	return newCommand;
}

string CInterpreter::CommandLegal(CUserCommand command) // 结合catalog判断命令是否可执行（语义检查）
{  
	Operation op = command.GetOperate();
	string tableName = command.GetTableName();
	string indexName = command.GetIndexName();
	string indexAttr = command.GetIndexAttr();

	try
	{	
		switch (op)
		{
		case OP_CREATE:
		{
			if (m_catalog->IsTableExist(tableName) != -1) // 这个表已经存在
				return "Table already exists"; // 退出
			vector<Attribute> tableAttrs = command.GetTableAttr();
			bool flag = false;
			for (int i = 0; i < tableAttrs.size(); ++i)
			{ 
				if (tableAttrs[i].attrName == command.GetPrimaryKey())  // primary key是表中的某个属性
				{
					flag = true; break;
				}
			}
			if (!flag) // primary key不是表中的某个属性
				return "Primary key attribute not exists";
			break;
		}
		case OP_DROP:
		{
			if (m_catalog->IsTableExist(tableName) == -1) // 这个表不存在
				return "Table not exists";
			break;
		}
		case OP_CREATE_INDEX:
		{
			if (m_catalog->IsTableExist(tableName) == -1) // 这个表不存在
				return "Table not exists";
			if (m_catalog->IsIndexExist(indexName)) // 这个index已经存在
				return "Index already exists";
			if (m_catalog->IsAttrExist(tableName, indexAttr) == -1) // 这个属性不是表中的属性
				return "Attribute not exist";
			break;
		}
		case OP_DROP_INDEX:
		{
			if (!m_catalog->IsIndexExist(indexName)) // 这个index不存在
				return "Index not exists";
			break;
		}
		case OP_SELECT:
		{
			vector<string> selectedCols = command.GetSelectCol();
			string col = selectedCols[0];

			if (m_catalog->IsTableExist(tableName) == -1) // 这个表不存在
				return "Table not exists";
			if (col != "*")
				for (int i = 0; i < selectedCols.size(); ++i)
				{
					col = selectedCols[i];
					if (m_catalog->IsAttrExist(tableName, col) == -1) // 如果这个被选中的列不存在
						return "Attribute '" + col + "' not exists";
				}
			break;
		}
		case OP_DELETE:
		{
			if (m_catalog->IsTableExist(tableName) == -1) // 这个表不存在
				return "Table not exists";
			break;
		}
		case OP_INSERT:
		{
			if (m_catalog->IsTableExist(tableName) == -1) // 这个表不存在
				return "Table not exists";
			//////////////////////////////判断插入的值的类型是不是按照表属性的类型的顺序排列////////////////////
			vector<string> values = command.GetInsertValue();
			vector<Attribute> attrs = m_catalog->GetAttrs(tableName);
			if (values.size() < attrs.size())
				return "Insert: Lack of values";
			if (values.size() > attrs.size())
				return "Insert: Too many values";
			for (int i = 0; i < attrs.size(); ++i)
			{
				int valueType = GetValueType(values[i]);
				switch (attrs[i].attrType)                 
				{
				case -1: // int
				{
					if (valueType != -1)
						return "Insert: Wrong value type";
					break;
				}
				case 0:
				{
					if (valueType != 0)
						return "Insert: Wrong value type";
					break;
				}
				default:
				{
					if (valueType == -1 || valueType == 0)
						return "Insert: Wrong value type";
					if (valueType > attrs[i].attrType) // 只要插入值的char长度大于表属性的char长度就不合格
						return "Insert: Wrong value type";
					break;
				}
				} // end of switch (attrs[i].attrType)
			} // end of for(i)
			break;
		} // end of case OP_INSERT
		} // end of swicth（op）
		if (op == OP_SELECT || op == OP_DELETE)
		{
			/////////////////////////////判断where条件的值的类型合不合格/////////////////////////
			vector<Condition> condition = command.GetCondition();
			int tableAttrType;
			for (int i = 0; i < condition.size(); ++i)
			{
				if (m_catalog->IsAttrExist(tableName, condition[i].conCol) == -1) // 用来比较的列不存在
					return "Colomn not exist";
				tableAttrType = m_catalog->GetAttrType(tableName, condition[i].conCol);
				switch(tableAttrType)
				{
				case -1:
				{
					if (condition[i].conValueType != -1)
						return "Wrong value type for comparision";
					break;
				}
				case 0:
				{
					if (condition[i].conValueType != 0)
						return "Wrong value type for comparision";
					break;
				}
				default:
				{   
					if (condition[i].conValueType > tableAttrType || condition[i].conValueType <= 0)
						return "Wrong value type for comparision";
					break;
				}
				} // end of switch 
			} // end of for（i）
		} // end of if（选择或者删除操作）
	
	}
	catch (CSysException e)
	{
		e.print();
	}
	return "Legal"; // 语义全部正确，可以执行该命令
}

void CInterpreter::printSelectResult(vector<vector<string>> result, CUserCommand command)
{
	if (result.size() == 0)
	{
		cout << "Empty set" << endl;
		return;
	}
	int len[33]; // 最终结果每一列的最长宽度
	vector<string> tableAttrs;
	
	// 获取要显示的列的名字存在tableAttrs
	if (command.GetSelectCol()[0] != "*")						
	{
		tableAttrs = command.GetSelectCol();
	}
	else
	{
		vector<Attribute> attrs = m_catalog->GetAttrs(command.GetTableName());
		for (int i = 0; i < attrs.size(); ++i)
			tableAttrs.push_back(attrs[i].attrName);
	}

	// 获取每一列的最长宽度存在len[]
	for (int i = 0; i < tableAttrs.size(); ++i) // 要显示的属性的数量
	{
		len[i] = tableAttrs[i].length(); // 属性名的长度也要考虑
		for (int j = 0; j < result.size(); ++j) // 表的数量
		{
			len[i] = max(len[i], result[j][i].length());
		}
	}

	// 输出表头
	for (int i = 0; i < tableAttrs.size(); ++i) //横线
	{
		cout << "+";
		cout << setw(len[0]+1) << setfill('-'); // 输出len长度的--
	}
	cout << "+" << endl;
	for (int i = 0; i < tableAttrs.size(); ++i)
	{
		cout << "|";
		cout << setw(len[0]) << setfill(' ') << tableAttrs[i]; // 属性名字
	}
	cout << "|" << endl;

	// 输出结果
	vector<string> row;
	for (int i = 0; i < result.size(); ++i)
	{
		row = result[i];
		for (int j = 0; j < row.size(); ++j)
		{
			cout << "|";
			cout << setw(len[j]) << row[j];
		}
		cout << endl;	
	}

	// 输出结尾
	for (int i = 0; i < tableAttrs.size(); ++i) //横线
	{
		cout << "+";
		cout << setw(len[0] + 1) << setfill('-'); // 输出len长度的--
	}
	cout << "+" << endl;

	if (result.size() == 1)
		cout << "1 row in set" << endl;
	else
		cout << result.size() << " rows in set" << endl;
}

void CInterpreter::Execute(CUserCommand command) throw(CSysException)// 执行用户命令并得到结果m
{
	Operation op = command.GetOperate();

	switch (op){
		case OP_QUIT: // 用户输入退出系统命令
		{
			QuitMiniSQL(); // 退出系统
			throw "quit";
			break;
		}
		case OP_EXEFILE: // 执行脚本文件
		{
			try{
				ExecuteFile(command);
			}
			catch (CSysException e){
				throw "quit";
			}
			break;
		}
		default: // 语法正确的数据库操作命令
		{
			string check = CommandLegal(command); // 结合catalog语义检查命令——可以执行
			if (check == "Legal") 
			{
				/////////////////////////调用API/////////////////////

				if (command.GetOperate() != OP_SELECT) // 非select操作
				{ 
					m_result = m_api->Execute(command);
					cout << m_result << endl;  // 输出执行反馈
				} else // select操作
				{
					vector<vector<string>> result = m_api->Select(command);
					printSelectResult(result, command); // 输出结果 
				} // end of select操作
			}
			else // 不能执行的数据库操作命令
			{
				CSysException e(check);
				throw e;
			} // end of if(legal)
		}
	} // end of switch
}

void CInterpreter::ExecuteFile(CUserCommand command) throw(CSysException)// 执行脚本文件
{
	string userInput = "";
	CUserCommand newCommand;
	string fileName = command.GetFileName();
	ifstream in(fileName);

	if (!in.is_open()) // 打开文件错误
	{
		cout << "Error: Cannot open the file!" << endl; return ;
	}
	while (!in.eof())
	{
		getline(in, userInput); // 读取文件中的一行命令
		
		try {
			newCommand = ParseCommand(userInput); // 语法检查，并将用户输入解析成内部命令
			Execute(newCommand); // 执行该条命令
		}
		catch (CSysException e){
			if (e.getError() != "quit")
				e.print();
			else
				throw "quit";
			continue;
		}
		cout << "===============================================================" << endl;
	}
	in.close();
}

void CInterpreter::QuitMiniSQL() // 退出系统
{
	cout <<  endl;
	cout << "MiniSQL is quitting... Bye!" << endl;
	Sleep(1500);
}

bool IsComEnd(string s)
{
	if (s == "")
		return false;
	if (s[s.length()-1] == ';') // 判断结尾是‘;’则该命令输入结束
		return true;
	return false;
}